package gms

import (
	"fmt"
	"html/template"
	"io"
	"net/http"
	"path/filepath"
	"reflect"
	"strings"
)

type Route struct {
	view, viewSuffix string
	handle           http.Handler
	handles          map[string][]reflect.Value
}

func NewRoute() *Route {
	handles := make(map[string][]reflect.Value)
	return &Route{handles: handles}
}

func (self *Route) Public(val string) *Route {
	self.handle = http.FileServer(http.Dir(val))
	return self
}

func (self *Route) View(val, subffix string) *Route {
	self.view = val
	self.viewSuffix = subffix
	return self
}

func (self *Route) Handle(handle interface{}) *Route {
	ty := reflect.ValueOf(handle).Type()
	for i := 0; i < ty.NumMethod(); i++ {
		fv := ty.Method(i)
		self.handles[fv.Name] = []reflect.Value{reflect.ValueOf(handle), reflect.ValueOf(fv)}
	}
	return self
}

func (self *Route) Tmpl(file string, wr io.Writer, data interface{}) error {
	if len(file) > 0 {
		name := filepath.Base(file)
		tmpl := template.New(fmt.Sprintf("%s%s", name, self.viewSuffix))
		tmpl, err := tmpl.ParseFiles(fmt.Sprintf("%s/%s%s", self.view, file, self.viewSuffix))
		if err != nil {
			return err
		}
		return tmpl.Execute(wr, data)
	}
	return nil
}

func onHandle(route *Route, w http.ResponseWriter, r *http.Request) {
	k := toMethod(r.URL.Path)
	if v, ok := route.handles[k]; ok {
		v[1].Interface().(reflect.Method).Func.Call([]reflect.Value{
			v[0],
			reflect.ValueOf(route),
			reflect.ValueOf(w),
			reflect.ValueOf(r)})
	} else if route.handle != nil {
		route.handle.ServeHTTP(w, r)
	}
}

func toMethod(path string) string {
	if strings.HasSuffix(path, "/") {
		path = fmt.Sprintf("%sindex", path)
	}
	list := strings.Split(string([]byte(path)[1:len(path)]), "/")
	for i := 0; i < len(list); i++ {
		str := []byte(list[i])
		list[i] = fmt.Sprintf("%s%s", strings.ToUpper(string(str[0])), string(str[1:len(str)]))
	}
	return strings.Join(list, "")
}
